Technical Q&A QA1206
Video Output Components - Implementing QTVideoOutputGetIndSoundOutput on Mac OS X


Q: Mac OS X Ç… QTVideoOutputGetIndSoundOutput Çé¿ëïÇ∑ÇÈÇ…ÇÕÅAǫǧÇ∑ÇÍÇŒÇÊÇ¢Ç≈ǵÇÂǧǩÅHÅ@éÑÇ™éùǡǃǢÇÈÇÃÇÕÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇ≈ÇÕÇ»Ç≠ÅACore Audio ÉhÉâÉCÉoÇ≈Ç∑ÅBÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇÕǫDZǩÇÁì¸éËÇ∑ÇÍÇŒÇÊÇ¢Ç≈ǵÇÂǧǩÅH

A: Carbon Sound Manager ÇÕÅAÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇ Mac OS X ÇÃäe Core Audio ÉfÉoÉCÉXÉhÉâÉCÉoÇ…ëŒâûÇ∑ÇÈÉTÉuÉ^ÉCÉv (subType) kHALCustomComponentSubType Ç…ìoò^ǵNjÇ∑ÅBégópǵǃǢÇÈ Core Audio ÉfÉoÉCÉXópÇÃÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇå©Ç¬ÇØÇÈÇ…ÇÕÅAà»â∫ÇÃéËèáÇé¿çsǵNjÇ∑ÅF

  1. Core Audio ÇégǡǃÉhÉâÉCÉoÇÃÉÜÉjÅ[ÉN ID(UID) Çí≤Ç◊Ç‹Ç∑ÅB
  2. Sound Manager Çèâä˙âªÇµÇ‹Ç∑ÅBDZÇÍÇÕÅASndManagerStatus ǻǫÇÃà¿âøÇ»åƒÇ—èoǵÇégǡǃçsǶNjÇ∑ÅB
  3. ÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgëSëÃÇ…ëŒÇµÇƒ FindNextComponent ÇåJÇËï‘ǵé¿çsǵÅAå©Ç¬Ç©Ç¡ÇΩäeÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇ≤ÇΔÇ…ÅAsiHALAudioDeviceUniqueID ÉZÉåÉNÉ^Çégǡǃ SoundComponentGetInfo ÇåƒÇ—èoǵNjÇ∑ÅB
  4. Core Audio Ç©ÇÁï‘Ç≥ÇÍÇΩÉhÉâÉCÉoÇà UID ÇΔÅASoundComponentGetInfo Ç©ÇÁï‘Ç≥ÇÍÇΩ UID ÇìÀÇ´çáÇÌÇπÇ‹Ç∑ÅB
  5. UID Ç™àÍívÇ∑ÇÍÇŒÅAÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇå©Ç¬ÇØÇΩDZÇΔÇ…Ç»ÇÈÇÃÇ≈ÅAǪÇÍÇï‘ǵÇΩÇÁèIóπÇ≈Ç∑ÅB

ÉäÉXÉg 1 ÇÕÅAíPàÍÇÃÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇÉTÉ|Å[ÉgÇ∑ÇÈÅAçlǶÇÁÇÍÇÈé¿ëïó·Çà 1 ǬÇ≈Ç∑ÅB


#define kMaxStringSize 1024

// CopyMyAudioDriverUID
// ÉhÉâÉCÉoÇà UID Çå©Ç¬ÇØÇƒÅA
// âï˙Ç∑Ç◊Ç´ CFString Ç…ï‘Ç∑
OSStatus CopyMyAudioDriverUID(CFStringRef *outUID)
{
    UInt32          theSize;
    char            theString[kMaxStringSize];
    UInt32          theNumberDevices;
    AudioDeviceID   *theDeviceList = NULL;
    UInt32          theDeviceIndex;
    CFStringRef     theCFString = NULL;
    OSStatus        theStatus = noErr;

    // DZÇÍÇ™ÉhÉâÉCÉo
    const char      *nameString = "BrownSound audio controller";
    const char      *manufacturerString = "Eddie";

    *outUID = NULL;

    // ÉfÉoÉCÉXÉäÉXÉgÇÃÉTÉCÉY
    theSize = 0;
    theStatus = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &theSize, NULL);
    if (theStatus) goto done;

    theNumberDevices = theSize / sizeof(AudioDeviceID);

    // ÉfÉoÉCÉXÉäÉXÉgÇäÑÇËìñǃÇÈ
    theDeviceList = (AudioDeviceID*)malloc(theNumberDevices * sizeof(AudioDeviceID));

    // ÉfÉoÉCÉXÉäÉXÉgÇéÊìæÇ∑ÇÈ
    theSize = theNumberDevices * sizeof(AudioDeviceID);
    theStatus = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &theSize, theDeviceList);

    // ÉfÉoÉCÉXÉäÉXÉgëSëÃÇ…ëŒÇµÇƒîΩïúèàóùÇçsÇ¢ÅA
    // ÉfÉoÉCÉXÇå©Ç¬ÇØÇƒ UID Çï‘Ç∑
    for(theDeviceIndex = 0; theDeviceIndex < theNumberDevices; ++theDeviceIndex)
    {
        // ñºëOÇéÊìæÇ∑ÇÈ
        theSize = kMaxStringSize;
        theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex],
                                      0, 0, kAudioDevicePropertyDeviceName, &theSize, theString);
        if (theStatus) goto done;

        // àÍívǵǃǢÇÈÇ©ÅH
        if (strncmp(theString, nameString, strlen(nameString)) == 0) {

            // ÉÅÅ[ÉJÅ[èÓïÒÇéÊìæÇ∑ÇÈ
            theSize = kMaxStringSize;
            theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex], 0, 0,
                                     kAudioDevicePropertyDeviceManufacturer, &theSize, theString);
            if (theStatus) goto done;

            // ñ{ìñÇ…àÍívǵǃǢÇÈÇ©ÅH
            if (strncmp(theString, manufacturerString, strlen(manufacturerString)) == 0) {
                // ÉfÉoÉCÉXÇà UID ÇéÊìæÇ∑ÇÈ
                theSize = sizeof(CFStringRef);
                theStatus = AudioDeviceGetProperty(theDeviceList[theDeviceIndex],
                                 0, 0, kAudioDevicePropertyDeviceUID, &theSize, &theCFString);
                if (theStatus) goto done;
                *outUID = theCFString;
                break;
            }
        }
    }

    // ÉfÉoÉCÉXÇÕå©Ç¬ÇÁǻǢ
    if (NULL == *outUID) theStatus = badComponentType;

done:
    // ÉfÉoÉCÉXÉäÉXÉgÇâï˙Ç∑ÇÈ
    if (theDeviceList) free(theDeviceList);

    return theStatus;
}

// QTVideoOutputGetIndSoundOutput
// ÉCÉìÉfÉbÉNÉXÉpÉâÉÅÉ^Ç≈éwíËÇ≥ÇÍÇΩÉrÉfÉIèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇÃ
// ÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇï‘Ç∑ÅBç≈èâÇÃÉRÉìÉ|Å[ÉlÉìÉgÇÃ
// ÉCÉìÉfÉbÉNÉXÇÕ 1
pascal ComponentResult MyVOut_GetIndSoundOutput(MyVOutGlobalsPtr storage,
                                                 long index, Component *outputComponent)
{
    Component            c = 0;
    ComponentDescription cd = { kSoundOutputDeviceType, kHALCustomComponentSubType, 0, 0, 0 };
    CFStringRef          myUID = NULL;
    CFStringRef          halUID = NULL;
    SMStatus             ignore;
    ComponentResult      err;

    *outputComponent = NULL;

    // ÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇÕ 1 ǬǵǩǻǢÇΩÇfl
    // ÉCÉìÉfÉbÉNÉXÇ™ 1 à»äOÇÃèÍçáÇÕÉGÉâÅ[ÇΔÇ»ÇÈ
    if (index != 1) return paramErr;

    // Ç∑Ç≈DždžÇÈÇΩÇflÅAèIóπ
    if (storage->soundOutput) {
        *outputComponent = storage->soundOutput;
        return noErr;
    }

    // core audio ÇégǡǃÅAÉIÅ[ÉfÉBÉIÉhÉâÉCÉo ID Çå©Ç¬ÇØÇÈ
    err = CopyMyAudioDriverUID(&myUID);
    if (err) goto bail;

    // Sound Manager Çà¿âøÇ»ï˚ñ@Ç≈èâä˙âªÇ∑ÇÈÅBSound Manager ÇÕÉVÉXÉeÉÄè„ÇÃ
    // Core Audio ÉhÉâÉCÉoÇ≤ÇΔÇ…ÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇçáê¨Ç∑ÇÈÇΩÇflÅA
    // DZÇÃèàóùÇ™ïKóv

    SndManagerStatus(sizeof(SMStatus), &ignore);

    // çáê¨Ç≥ÇÍÇΩÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇå©Ç¬ÇØÇÈ
    while (c = FindNextComponent(c, &cd)) {
        // ï‘Ç≥ÇÍÇΩ CFString Çâï˙ǵǻǢ
        err = SoundComponentGetInfo(c, 0, siHALAudioDeviceUniqueID, &halUID);
        if (err) goto bail;

        // àÍívÇ∑ÇÍÇŒê¨å˜
        if (CFEqual(myUID, halUID)) {
            *outputComponent = c;
            storage->soundOutput = c;
            break;
        }
    }

    // ëŒâûÇ∑ÇÈ sDev Ç™å©Ç¬Ç©ÇÁǻǢ
    if (NULL == *outputComponent) err = badComponentType;

bail:
    if (myUID) CFRelease(myUID);

    return err;
}                

ÉäÉXÉg 1.


íçà”ÅFÉVÉXÉeÉÄè„ÇÃäe Core Audio ÉhÉâÉCÉoÇ≤ÇΔÇ…ÉTÉEÉìÉhèoóÕÉRÉìÉ|Å[ÉlÉìÉgÇìoò^Ç≈Ç´ÇÈÇÊǧDžÅAç≈èâÇ… Carbon Sound Manager Çèâä˙âªÇ∑ÇÈïKóvǙdžÇËÇ‹Ç∑ÅBèâä˙âªÇé¿çsÇ∑ÇÈà¿âøÇ»ï˚ñ@ÇΔǵǃÇÕÅAÇ∑Ç◊ǃÇà SoundComponentGetInfo ÇÃåƒÇ—èoǵÇÃëOÇ…ÅASndManagerStatus ÇåƒÇ—èoÇ∑Ç‚ÇËï˚ǙdžÇËÇ‹Ç∑ÅB


[2002 îN 10 åé 29 ì˙]